package com.mandy.datamerge.spring;

import com.google.common.collect.Maps;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Supplier;

/**
 * @className ApplicationContextHolder
 * @description Spring Bean 获取工具类
 * @author jianyongjie@126.com
 * @date 2020/7/3 10:13 上午
 * @version 1.0.0
 **/
@Component
public class ApplicationContextHolder implements BeanFactoryPostProcessor, ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private static Map<Class<?>, String> nameMap = Maps.newHashMap();

    public ApplicationContextHolder() {
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return getBean(clazz, () -> {
            throw new RuntimeException("类:" + clazz + "没有相应的spring定义");
        });
    }

    public static <T> T getBean(Class<T> clazz, Supplier<T> ifAbsent) {
        String beanName = nameMap.get(clazz);
        if (beanName == null) {
            String[] beanNames = applicationContext.getBeanNamesForType(clazz);
            if (beanNames.length == 0) {
                return ifAbsent.get();
            }

            if (beanNames.length > 1) {
                throw new RuntimeException("类:" + clazz + "有多个bean定义:" + Arrays.toString(beanNames));
            }

            beanName = beanNames[0];
            nameMap.put(clazz, beanName);
        }

        return (T) applicationContext.getBean(beanName);
    }

    public static <T> T getInstance(Class<T> clazz) {
        String beanName = nameMap.get(clazz);
        if (beanName == null) {
            String[] beanNames = applicationContext.getBeanNamesForType(clazz);
            if (beanNames.length == 0) {
                throw new RuntimeException("类:" + clazz + "没有相应的spring定义");
            }

            if (beanNames.length > 1) {
                throw new RuntimeException("类:" + clazz + "有多个bean定义:" + Arrays.toString(beanNames));
            }

            beanName = beanNames[0];
            nameMap.put(clazz, beanName);
        }

        return (T) applicationContext.getBean(beanName);
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}